home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload Trio 2
/
Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO
/
dir24
/
jnos110g.zip
/
NNTPCLI.C
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-26
|
31KB
|
966 lines
/*
* Client routines for Network News Tranfer Protocol ala RFC977
*
* Copyright 1990 Anders Klemets - SM0RGV, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*
* Changes copyright 1990 Bernie Roehl, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*
* Revision history:
*
* May 11, 1990 - br checked for invalid chars in news filenames
*
* May 10, 1990 - br changed date stamp in 'From ' lines to
* seconds since GMT (to make parsing and expiry easier)
*
* May 9, 1990 - br added locking of nntp.dat and history files,
* second parameter to NNTP DIR, fixed bug in updating of
* nntp.dat
*
* early May, 1990 -- br added NNTP TRACE, NNTP DIR,
* server-specific newsgroups and connection windows,
* locking of newsgroup files using mlock() and rmlock(),
* date stamping of 'From ' lines, increased stack space,
* updating of nntp.dat only on successful sessions.
*
* July 19, 1990 pa0gri Delinted and cleaned up. (calls and includes)
*
* Jun 30, 1994 n5knx Added timestamp to history file to aid expiration,
* and build index if newsgroup is stored under Mailspool. Create
* ng.inf timestamp file if ng is in areas file.
* Jul 1994 n5knx reimplemented newsgroup name mapping. Disallow kicking
* a running process. Avoid --more-- wait when !nntpquiet tracing.
* Add LZW support by N8FOW. Compensate for GMT.
*/
#include <sys/types.h>
#include <time.h>
#include <sys/timeb.h>
#include <ctype.h>
#ifdef __TURBOC__
#include <dir.h>
#endif
#include "global.h"
#ifdef NNTP
#include "timer.h"
#include "cmdparse.h"
#include "commands.h"
#include "socket.h"
#include "usock.h"
#include "netuser.h"
#include "proc.h"
#include "session.h"
#include "smtp.h"
#include "mailutil.h"
#include "files.h"
#include "bm.h"
#include "index.h"
#ifdef LZW
#include "lzw.h"
#endif
#define NNTPMAXLEN 512
struct nntpservers {
struct timer nntpcli_t;
char *name;
char *groups;
int lowtime, hightime; /* for connect window */
struct nntpservers *next;
};
#define NULLNNTP (struct nntpservers *)NULL
struct ngmap {
char *prefix; /* e.g. comp, rec.radio, net, talk, alt ... */
char *newname; /* what prefix should be changed to */
struct ngmap *next; /* link to next entry */
};
static struct nntpservers *Nntpservers = NULLNNTP;
static char *Nntpgroups = NULLCHAR;
static unsigned short nntptrace = 1;
static int nntpquiet = 0;
static int Nntpfirstpoll = 5;
static char *News_spool = NULL;
static int np_all = 0; /* non-zero if Newsdir is a malloc'ed space */
static struct ngmap *ngmaphead = NULL;
static char validchars[] = "abcdefghijklmnopqrstuvwxyz0123456789-_.";
static char WOpenMsg[] = "NNTP window to '%s' not open\n";
static char CFailMsg[] = "NNTP %s: Connect failed: %s";
static char BadBannerMsg[] = "NNTP %s: bad reply on banner (response was %d)";
static char NoLockMsg[] = "NNTP %s: Cannot lock %s";
static char NoOpenMsg[] = "NNTP %s: Cannot open %s";
static char NoUpdateMsg[] = "NNTP %s: Could not update %s";
static char ProtoErrMsg[] = "NNTP %s: Protocol error (response was %d)";
static char GTFailMsg[] = "NNTP %s: Giving up: gettxt() failure";
static char GAFailMsg[] = "NNTP %s: Giving up: could not get article";
static void nntptick __ARGS((void *tp));
static void nntp_job __ARGS((int i1,void *tp,void *v1));
static int gettxt __ARGS((int s,FILE *fp));
static int getreply __ARGS((int s));
static int getarticle __ARGS((int s,char *msgid, char *nglist));
static int dogroups __ARGS((int argc,char *argv[],void *p));
static int doadds __ARGS((int argc,char *argv[],void *p));
static int dodrops __ARGS((int argc,char *argv[],void *p));
static int dokicks __ARGS((int argc,char *argv[],void *p));
static int dolists __ARGS((int argc,char *argv[],void *p));
static int donntrace __ARGS((int argc,char *argv[],void *p));
static int donnquiet __ARGS((int argc,char *argv[],void *p));
static int dondir __ARGS((int argc,char *argv[],void *p));
static int donnfirstpoll __ARGS((int argc,char *argv[],void *p));
static void make_time_string(char *string,time_t *timep);
#ifdef LZW
static int donnlzw __ARGS((int argc,char *argv[],void *p));
int LzwActive = 1;
#endif
/* Tracing levels:
0 - no tracing
1 - serious errors reported
2 - transient errors reported
3 - session progress reported
4 - actual received articles displayed
*/
static struct cmds Nntpcmds[] = {
"addserver", doadds, 0, 3,
"nntp addserver <nntpserver> <interval> [<groups>]",
"directory", dondir, 0, 0, NULLCHAR,
"dropserver", dodrops, 0, 2, "nntp dropserver <nntpserver>",
"firstpoll", donnfirstpoll, 0, 0, NULLCHAR,
"groups", dogroups, 0, 0, NULLCHAR,
"kick", dokicks, 0, 2, "nntp kick <nntpserver>",
"listservers", dolists, 0, 0, NULLCHAR,
#ifdef LZW
"lzw", donnlzw, 0, 0, NULLCHAR,
#endif
"quiet", donnquiet, 0, 0, NULLCHAR,
"trace", donntrace, 0, 0, NULLCHAR,
NULLCHAR,
};
int
donntp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Nntpcmds,argc,argv,p);
}
static int
doadds(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nntpservers *np;
for(np = Nntpservers; np != NULLNNTP; np = np->next)
if(stricmp(np->name,argv[1]) == 0)
break;
if (np == NULLNNTP) {
np = (struct nntpservers *) callocw(1,sizeof(struct nntpservers));
np->name = strdup(argv[1]);
np->next = Nntpservers;
Nntpservers = np;
np->groups = NULLCHAR;
np->lowtime = np->hightime = -1;
np->nntpcli_t.func = nntptick; /* what to call on timeout */
np->nntpcli_t.arg = (void *)np;
}
if (argc > 3) {
int i;
if (np->groups == NULLCHAR) {
np->groups = mallocw(NNTPMAXLEN);
*np->groups = '\0';
}
for (i = 3; i < argc; ++i) {
if (isdigit(*argv[i])) {
int lh, ll, hh, hl;
sscanf(argv[i], "%d:%d-%d:%d", &lh, &ll, &hh, &hl);
np->lowtime = lh * 100 + ll;
np->hightime = hh * 100 + hl;
} else if ((strlen(np->groups)+strlen(argv[i])+2) >= NNTPMAXLEN)
tprintf("Group list too long! Group '%s' ignored!\n", argv[i]);
else { /* it's a group, and it fits... add it to list */
if (*np->groups != '\0')
strcat(np->groups, ",");
strcat(np->groups, argv[i]);
}
}
if (*np->groups == '\0') { /* No groups specified? */
free(np->groups);
np->groups = NULLCHAR;
}
}
/* set timer duration */
set_timer(&np->nntpcli_t,atol(argv[2])*1000L);
start_timer(&np->nntpcli_t); /* and fire it up */
return 0;
}
static int
dodrops(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nntpservers *np, *npprev = NULLNNTP;
for(np = Nntpservers; np != NULLNNTP; npprev = np, np = np->next)
if(stricmp(np->name,argv[1]) == 0) {
stop_timer(&np->nntpcli_t);
free(np->name);
if (np->groups)
free(np->groups);
if(npprev != NULLNNTP)
npprev->next = np->next;
else
Nntpservers = np->next;
free((char *)np);
return 0;
}
tputs("No such server enabled.\n");
return 0;
}
static int
dolists(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nntpservers *np;
for(np = Nntpservers; np != NULLNNTP; np = np->next) {
char tbuf[80];
if (np->lowtime != -1 && np->hightime != -1)
sprintf(tbuf, " -- %02d:%02d-%02d:%02d", np->lowtime/100, np->lowtime%100, np->hightime/100, np->hightime%100);
else
tbuf[0] = '\0';
tprintf("%-32s (%lu/%lu%s) %s\n", np->name,
read_timer(&np->nntpcli_t) /1000L,
dur_timer(&np->nntpcli_t) /1000L,
tbuf, np->groups ? np->groups : "");
}
return 0;
}
#ifdef LZW
/* Sets LzwActive flag */
static int
donnlzw(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&LzwActive,"NNTP lzw",argc,argv);
}
#endif /* LZW */
static int donntrace(argc, argv, p)
int argc;
char *argv[];
void *p;
{
return setshort(&nntptrace,"NNTP tracing",argc,argv);
}
static int donnquiet(argc, argv, p)
int argc;
char *argv[];
void *p;
{
return setbool(&nntpquiet,"NNTP quiet",argc,argv);
}
static int
donnfirstpoll(argc,argv,p) /* from G8FSL */
int argc;
char *argv[];
void *p;
{
return setint(&Nntpfirstpoll,"NNTP polls new server for news over last <n> days",argc,argv);
}
static void
make_time_string(char *string,time_t *timep)
{
struct tm *stm;
stm = localtime(timep);
sprintf(string,"%02d%02d%02d %02d%02d%02d",
stm->tm_year%100,stm->tm_mon + 1,stm->tm_mday,stm->tm_hour,
stm->tm_min,stm->tm_sec);
}
static int dondir(argc, argv, p)
int argc;
char *argv[];
void *p;
{
struct ngmap *ngp, *prev_ngp;
if (argc < 2) {
int i;
tprintf("spool: %s\n", News_spool ? News_spool : Mailspool);
tprintf("control: %s\n", Newsdir);
for (ngp = ngmaphead; ngp != NULL; ngp=ngp->next)
if (ngp->prefix) tprintf("%s = %s\n", ngp->prefix, ngp->newname);
} else {
char *p;
if ((p = strchr(argv[1], '=')) != NULLCHAR) { /* set a prefix mapping */
int i;
*p++ = '\0';
for (ngp=ngmaphead, prev_ngp=NULL; ngp != NULL; prev_ngp=ngp, ngp=ngp->next)
if (ngp->prefix)
if (!stricmp(ngp->prefix, argv[1])) {
if (ngp->newname) {
free(ngp->newname);
ngp->newname = NULLCHAR;
}
if (*p == '=') {
free(ngp->prefix);
ngp->prefix = NULLCHAR;
} else
ngp->newname = strdup(p);
return 0;
}
if (*p == '=') /* trashing a mapping that's not there */
return 0;
ngp=mallocw(sizeof (struct ngmap));
ngp->prefix = strdup(argv[1]);
ngp->newname = strdup(p);
ngp->next = (struct ngmap *)NULL;
if (prev_ngp) prev_ngp->next = ngp;
else ngmaphead = ngp;
return 0;
}
else /* no '=', so just set default */
{
if (News_spool)
free(News_spool);
News_spool = strdup(argv[1]);
}
if (argc > 2) { /* they specified a newsdir as well */
if (np_all)
free(Newsdir);
Newsdir = strdup(argv[2]);
np_all = 1;
}
}
return 0;
}
static int
dokicks(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct nntpservers *np;
for(np = Nntpservers; np != NULLNNTP; np = np->next)
if(stricmp(np->name,argv[1]) == 0) {
/* If the timer is not running, the timeout function has
* already been called, so we don't want to start another process.
*/
if(run_timer(&np->nntpcli_t)) {
stop_timer(&np->nntpcli_t);
nntptick((void *)np);
}
return 0;
}
tputs("No such server enabled.\n");
return 1;
}
static int
dogroups(argc,argv,p)
int argc;
char *argv[];
void *p;
{
int i;
if(argc < 2) {
if(Nntpgroups == NULLCHAR || (Nntpgroups != NULLCHAR && strcmp(Nntpgroups,"*") == 0))
tputs("All groups are currently enabled.\n");
else
tprintf("Currently enabled newsgroups:\n%s\n",Nntpgroups);
return 0;
}
if(Nntpgroups == NULLCHAR)
Nntpgroups = mallocw(NNTPMAXLEN);
*Nntpgroups = '\0';
for(i=1; i < argc; ++i) {
if(i > 1)
strcat(Nntpgroups,",");
strcat(Nntpgroups,argv[i]);
}
return 0;
}
/* This is the routine that gets called every so often to connect to
* NNTP servers.
*/
static void
nntptick(tp)
void *tp;
{
if (newproc("NNTP client", 3072, nntp_job, 0, tp, NULL,0) == NULLPROC)
start_timer(&((struct nntpservers *)tp)->nntpcli_t); /* N5KNX: retry later */
}
static void
nntp_job(i1,tp,v1)
int i1;
void *tp, *v1;
{
FILE *fp, *tmpf;
int s = -1, i;
/* long pos; */
struct tm *ltm;
time_t t;
int now;
struct nntpservers *np = (struct nntpservers *) tp;
struct sockaddr_in fsocket;
char tbuf[NNTPMAXLEN], buf[NNTPMAXLEN], *cp, *lastdate = NULLCHAR;
char currdate[20];
char GMT[] = " GMT";
#ifdef LZW
int lzwmode, lzwbits, ret;
extern int16 Lzwbits;
extern int Lzwmode;
#endif /* LZW */
if (nntptrace >= 3)
tprintf("NNTP daemon entered, target = %s\n",np->name);
if(availmem() < Memthresh + 4000L){
if (nntptrace >= 2)
tputs("NNTP daemon quit -- low memory\n");
/* Memory is tight, don't do anything */
start_timer(&np->nntpcli_t);
return;
}
time(&t); /* more portable than gettime() */
ltm = localtime(&t);
now = ltm->tm_hour * 100 + ltm->tm_min;
if (np->lowtime < np->hightime) { /* doesn't cross midnight */
if (now < np->lowtime || now >= np->hightime) {
if (nntptrace >= 3)
tprintf(WOpenMsg, np->name);
start_timer(&np->nntpcli_t);
return;
}
} else {
if (now < np->lowtime && now >= np->hightime) {
if (nntptrace >= 3)
tprintf(WOpenMsg, np->name);
start_timer(&np->nntpcli_t);
return;
}
}
fsocket.sin_addr.s_addr = resolve(np->name);
if(fsocket.sin_addr.s_addr == 0) { /* No IP address found */
if (nntptrace >= 2)
tprintf("NNTP can't resolve host '%s'\n", np->name);
/* Try again later */
start_timer(&np->nntpcli_t);
return;
}
fsocket.sin_family = AF_INET;
fsocket.sin_port = IPPORT_NNTP;
s = socket(AF_INET,SOCK_STREAM,0);
sockmode(s,SOCK_ASCII);
if(connect(s,(char *)&fsocket,SOCKSIZE) == -1){
cp = sockerr(s);
if (!cp) cp="";
log(s,CFailMsg,psocket(&fsocket),cp);
if (nntptrace >= 2)
tprintf(CFailMsg,psocket(&fsocket),cp), tputc('\n');
goto quit;
}
/* Eat the banner */
i = getreply(s);
if(i == -1 || i >= 400) {
log(s,BadBannerMsg,psocket(&fsocket),i);
if (nntptrace >= 1)
tprintf(BadBannerMsg,psocket(&fsocket),i), tputc('\n');
goto quit;
}
#ifdef LZW
if(LzwActive) {
usprintf(s,"XLZW %d %d\n",Lzwbits,Lzwmode);
usflush(s);
if(recvline(s,buf,NNTPMAXLEN) == -1)
goto quit;
rip(buf);
ret = lzwmode = lzwbits = 0;
sscanf(buf,"%d %d %d",&ret,&lzwbits,&lzwmode);
/* Eat negative response */
if((ret >= 200) && (ret < 300)) {
if(lzwmode != Lzwmode || lzwbits != Lzwbits) {
lzwmode = LZWCOMPACT;
lzwbits = LZWBITS;
}
lzwinit(s,lzwbits,lzwmode);
}
/* else not supported */
}
#endif /* LZW */
if (mlock(Newsdir, "nntp")) {
log(s,NoLockMsg, psocket(&fsocket), "nntp.dat");
if (nntptrace >= 2)
tprintf(NoLockMsg, psocket(&fsocket), "nntp.dat\n");
goto quit;
}
sprintf(buf,"%s/nntp.dat",Newsdir);
if((fp = fopen(buf,APPEND_TEXT)) == NULLFILE) {
log(s,NoOpenMsg,psocket(&fsocket),buf);
if (nntptrace >= 1)
tprintf(NoOpenMsg,psocket(&fsocket),buf), tputc('\n');
rmlock(Newsdir, "nntp");
goto quit;
}
rewind(fp);
/* for(pos=0L; fgets(buf,NNTPMAXLEN,fp) != NULLCHAR;pos=ftell(fp)) { */
for(; fgets(buf,NNTPMAXLEN,fp) != NULLCHAR;) {
if((cp = strchr(buf,' ')) == NULLCHAR)
continue; /* something wrong with this line, skip it */
*cp = '\0';
if(stricmp(buf,np->name) == 0) {
rip(cp+1);
lastdate = strdup(cp+1);
break;
}
}
fclose(fp);
rmlock(Newsdir, "nntp");
if(lastdate == NULLCHAR) {
if (Nntpfirstpoll < 0)
lastdate = strdup("900101 000000");
else { /* from G8FSL */
lastdate = mallocw(15);
time(&t);
t -= Nntpfirstpoll*86400L;
make_time_string(lastdate,&t);
}
}
/* snapshot the time for use later in re-writing nntp.dat */
time(&t);
/* N5KNX: we must tell the nntp server if our reference time is UTC/GMT or local time. */
#ifdef MSDOS
ltm = localtime(&t); /* localtime calls tzset() which sets timezone */
if (timezone == 0L) strcpy(GMT, " GMT"); /* you get EST if TZ env var is unset */
else GMT[0] = '\0';
#else
ltm = gmtime(&t); /* BSD vs SysV vs Linux vs Apple vs ??? */
i = ltm->tm_hour;
ltm = localtime(&t);
if (i == ltm->tm_hour) strcpy(GMT, " GMT");
else GMT[0] = '\0';
#endif
sprintf(currdate,"%02d%02d%02d %02d%02d%02d",ltm->tm_year%100,ltm->tm_mon+1,
ltm->tm_mday,ltm->tm_hour,ltm->tm_min,ltm->tm_sec);
/* Get a list of new message-id's */
if (np->groups) cp=np->groups;
else cp=Nntpgroups != NULLCHAR ? Nntpgroups : "*";
if (nntptrace >= 3)
tprintf("==>NEWNEWS %s %s%s\n", cp, lastdate, GMT);
usprintf(s,"NEWNEWS %s %s%s\n", cp, lastdate, GMT);
free(lastdate);
/* Get the response */
if((i = getreply(s)) != 230) { /* protocol error */
log(s,ProtoErrMsg,psocket(&fsocket),i);
if (nntptrace >= 1)
tprintf(ProtoErrMsg,psocket(&fsocket),i), tputc('\n');
goto quit;
}
if((tmpf = tmpfile()) == NULLFILE) {
if (nntptrace >= 1)
tprintf(NoOpenMsg, psocket(&fsocket), "tmpfile\n");
goto quit;
}
if(gettxt(s,tmpf) == -1) {
log(s, GTFailMsg, psocket(&fsocket));
if (nntptrace >= 1)
tprintf(GTFailMsg,psocket(&fsocket)), tputc('\n');
fclose(tmpf);
goto quit;
}
/* Open the history file */
i=0;
while (mlock(History, NULLCHAR)) {
pause(1000L);
if (++i == 60) {
log(s, NoLockMsg, psocket(&fsocket), History);
if (nntptrace >= 1)
tprintf(NoLockMsg, psocket(&fsocket), History), tputc('\n');
fclose(tmpf);
goto quit;
}
}
if((fp = fopen(History,APPEND_TEXT)) == NULLFILE) {
log(s,NoOpenMsg, psocket(&fsocket), History);
if (nntptrace >= 1)
tprintf(NoOpenMsg,psocket(&fsocket),History), tputc('\n');
fclose(tmpf);
goto quit;
}
/* search through the history file for matching message id's */
rewind(tmpf);
while(fgets(tbuf,NNTPMAXLEN,tmpf) != NULLCHAR) {
rip(tbuf);
i = 0;
rewind(fp);
while(fgets(buf,NNTPMAXLEN,fp) != NULLCHAR) {
if(strnicmp(buf,tbuf,strlen(tbuf)) == 0) {
i = 1;
break;
}
pwait(NULL);
}
if(i == 0) { /* not found, get the article */
if(getarticle(s,tbuf,cp) == -1) {
log(s,GAFailMsg,psocket(&fsocket));
if (nntptrace >= 2)
tprintf(GAFailMsg,psocket(&fsocket)), tputc('\n');
fclose(fp);
rmlock(History, NULLCHAR);
fclose(tmpf);
goto quit;
}
fprintf(fp,"%s %s\n",tbuf,currdate); /* add the new message id + timestamp */
}
}
fclose(fp);
rmlock(History, NULLCHAR);
fclose(tmpf);
if (nntptrace >= 3)
tputs("==>QUIT\n");
usputs(s,"QUIT\n");
/* Eat the response */
getreply(s);
/* NOW, update the nntp.dat file */
if (mlock(Newsdir, "nntp")) {
if (nntptrace >= 2)
tprintf(NoLockMsg, psocket(&fsocket), "nntp.dat (update)\n");
goto quit;
}
sprintf(buf,"%s/nntp.dat",Newsdir);
fp = fopen(buf,READ_TEXT);
sprintf(buf, "%s/nntp.tmp",Newsdir);
if ((tmpf = fopen(buf, WRITE_TEXT)) == NULLFILE)
if (nntptrace >= 1)
tprintf(NoOpenMsg,psocket(&fsocket),buf), tputc('\n');
if (fp == NULLFILE || tmpf == NULLFILE) {
log(s,NoUpdateMsg, psocket(&fsocket), buf);
if (nntptrace >= 2)
tprintf(NoUpdateMsg,psocket(&fsocket),buf), tputc('\n');
if (fp)
fclose(fp);
if (tmpf)
fclose(tmpf);
rmlock(Newsdir, "nntp");
goto quit;
}
while (fgets(tbuf, sizeof(tbuf), fp))
if (strnicmp(tbuf, np->name, strlen(np->name)))
fputs(tbuf, tmpf);
fprintf(tmpf,"%s %s\n",np->name,currdate);
fclose(fp);
fclose(tmpf);
sprintf(buf, "%s/nntp.dat", Newsdir);
sprintf(tbuf, "%s/nntp.tmp", Newsdir);
unlink(buf);
rename(tbuf, buf);
rmlock(Newsdir, "nntp");
quit:
if (nntptrace >= 3)
tputs("NNTP daemon exiting\n");
close_s(s);
/* Restart timer */
start_timer(&np->nntpcli_t);
return;
}
static int
gettxt(s,fp)
int s;
FILE *fp;
{
char buf[NNTPMAXLEN];
int nlines;
for (nlines = 0; recvline(s,buf,NNTPMAXLEN) != -1; ++nlines) {
if (nntptrace >= 4)
tprintf("<==%s", buf);
if(strcmp(buf,".\n") == 0) {
if (nntptrace >= 3)
tprintf("NNTP received %d lines\n", nlines);
return 0;
}
/* check for escaped '.' characters */
if(strcmp(buf,"..\n") == 0)
fputs(".\n",fp);
else
fputs(buf,fp);
}
if (nntptrace >= 1)
tprintf("NNTP receive error after %d lines\n", nlines);
return -1;
}
static int
getreply(s)
int s;
{
char buf[NNTPMAXLEN];
int response;
while(recvline(s,buf,NNTPMAXLEN) != -1) {
/* skip informative messages and blank lines */
if(buf[0] == '\0' || buf[0] == '1')
continue;
sscanf(buf,"%d",&response);
if (nntptrace >= 3)
tprintf("<==%s\n", buf);
return response;
}
if (nntptrace >= 3)
tputs("==No response\n");
return -1;
}
static int
getarticle(s,msgid,nglist)
int s;
char *msgid, *nglist;
{
char buf[NNTPMAXLEN], *froml=NULLCHAR, *newgl=NULLCHAR;
char ng[FILE_PATH_SIZE], *cp, *cp1;
FILE *fp, *tmpf;
int i;
extern int Smtpquiet;
time_t t;
long start;
struct mailindex ind;
if (nntptrace >= 3)
tprintf("==>ARTICLE %s\n", msgid);
usprintf(s,"ARTICLE %s\n", msgid);
i = getreply(s);
if(i == -1 || i >= 500)
return -1;
if(i >= 400)
return 0;
if((tmpf = tmpfile()) == NULLFILE) {
if (nntptrace >= 1)
tputs("NNTP Cannot open temp file for article\n");
return -1;
}
if(gettxt(s,tmpf) == -1) {
fclose(tmpf);
return -1;
}
/* convert the article into mail format */
rewind(tmpf);
while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
if(strncmp(buf,"From: ",6) == 0) {
rip(&buf[6]);
froml=strdup(&buf[6]);
if(newgl != NULLCHAR)
break;
}
if(strncmp(buf,"Newsgroups: ",12) == 0) {
newgl=strdup(&buf[12]);
if(froml != NULLCHAR)
break;
}
/* invalid article - missing 'From:' line or 'Newsgroups:' line */
if(strcmp(buf,"\n") == 0 && (froml == NULLCHAR || newgl == NULLCHAR)) {
/* fclose(fp); */
fclose(tmpf);
free(froml);
free(newgl);
return 0;
}
}
/* Clear the index to start */
memset(&ind,0,sizeof(ind));
for(i=0,cp=newgl;*cp;++cp) {
if(*cp == ',' || *cp == '\n') {
char *tempdir=NULLCHAR, *prefix, *p;
struct ngmap *ngp;
ng[i] = '\0';
/* is this article's newsgroup in our list? */
for(cp1=nglist; *cp1; ) {
int j;
if (*cp1 == '*') break; /* '*' always matches */
if ((j=strcspn(cp1,",")) != i || strnicmp(cp1, ng, i)) {
cp1 += j;
if (*cp1 == ',') cp1++;
}
else break; /* matches */
}
if (! *cp1) goto skipng;
/* map name of newsgroup as required */
for (ngp=ngmaphead; ngp!=NULL; ngp=ngp->next) {
int j;
if (ngp->prefix) {
if ((j=strlen(ngp->prefix)) > i) continue;
if (strnicmp(ng, ngp->prefix, j)) continue;
cp1=strdup(&ng[j]);
strcpy(ng, ngp->newname);
strcat(ng, cp1);
free(cp1);
i=strlen(ng);
/* we could 'break' here, but might be useful to allow further remaps */
}
}
/* make dirs associated with ng */
sprintf(buf,"%s/",News_spool ? News_spool : Mailspool);
for(cp1=ng; *cp1; ) {
if ((p=strchr(cp1,'.')) != NULLCHAR) {
*p = '\0';
strcat(buf, cp1);
#ifdef __TURBOC__
mkdir(buf); /* create a subdirectory, if necessary */
#else
mkdir(buf,0755); /* create a subdirectory, if necessary */
#endif
*p = '/';
cp1=p;
}
else {
prefix=cp1;
if (*prefix == '/') prefix++; /* first char after dot->slash */
break;
}
}
if ( (i=strlen(buf)) > 1 && buf[--i] == '/') buf[i] = '\0';
tempdir=strdup(buf);
strcat(buf,"/");
strcat(buf,prefix);
if (mlock(tempdir, prefix)) {
if (nntptrace >= 2)
tprintf("NNTP group '%s' is locked\n", ng);
free(froml);
free(newgl);
free(tempdir);
return -1;
}
if (! News_spool) SyncIndex(ng); /* ensure index file is current */
strcat(buf,".txt");
/* open the mail file */
if (nntptrace >= 3)
tprintf("Writing article to '%s'\n", buf);
if((fp = fopen(buf,APPEND_TEXT)) != NULLFILE) {
default_index(ng,&ind);
fseek(fp,0,SEEK_END);
start = ftell(fp);
time(&t);
fprintf(fp, "From %s %ld\n", froml, t);
#ifdef USERLOG
/* If the userlog code is enabled, we need a
* "Received: " line to get the message id
* that is used in it - WG7J
*/
ind.mydate=t;
ind.msgid = get_msgid();
fprintf(fp,Hdrs[RECEIVED]);
fprintf(fp,"by %s with NNTP\n\tid AA%ld ; %s",
Hostname, ind.msgid, ptime(&t));
#endif
rewind(tmpf);
while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
if(buf[0] == '\n') { /* End of headers */
putc('\n',fp);
break;
}
fputs(buf,fp);
rip(buf);
set_index(buf,&ind);
}
/* Now the remaining data */
while(fgets(buf,NNTPMAXLEN,tmpf) != NULLCHAR) {
/* for UNIX mail compatiblity */
if(strncmp(buf,"From ",5) == 0)
putc('>',fp);
fputs(buf,fp);
}
putc('\n',fp);
ind.size = ftell(fp) - start;
fclose(fp);
if(! News_spool) { /* working under Mailspool? */
#ifdef USERLOG
/* Now touch the timestamp file if it's an area */
if(isarea(ng)) { /* ve3lum 051494, n5knx */
sprintf(buf,"%s/%s.inf", tempdir, prefix);
fclose(fopen(buf,"w"));
}
#endif
/* Update the index file */
if (write_index(ng,&ind) == -1)
log(s,"NNTP can't update index for %s", ng);
}
}
rmlock(tempdir, prefix);
free(tempdir);
skipng:
if (*cp == '\n')
break;
i=0;
continue;
}
ng[i++] = strchr(validchars, tolower(*cp)) ? *cp : '_';
}
default_index("",&ind); /* Free remaining data in index structure */
fclose(tmpf);
rip(newgl); /* remove trailing new-line */
if(!nntpquiet) {
/* If we use tprintf here, instead of printf, flowcontrol
* in the command screen is used; if the system is unattended for
* more than 24 articles coming in, it will lock up NNTP.
* Make sure this only goes to the command screen - WG7J/N5KNX
*/
#ifdef LINUX
/* true, but we defeat that when using the trace interface anyway. KF8NH */
CmdOverride = 1;
tcmdprintf(stdout,"New news arrived: %s, article %s%c\n",newgl,msgid,Smtpquiet?' ':'\007');
#else
if(Current->output == Command->output)
printf("New news arrived: %s, article %s%c\n",newgl,msgid,Smtpquiet?' ':'\007');
#endif
}
free(froml);
free(newgl);
return 0;
}
#endif /* NNTP */